{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# `std::unique_ptr` vs `std::shared_ptr` 及自定义删除器\n",
    "\n",
    "| 智能指针             | 所有权语义                       | 开销                                 | 典型用途                                 |\n",
    "| -------------------- | -------------------------------- | ------------------------------------ | ---------------------------------------- |\n",
    "| `std::unique_ptr<T>` | 独占所有权，不可拷贝，可移动     | 零额外计数开销，与裸指针同等大小     | 管理唯一资源（文件句柄、socket、树节点） |\n",
    "| `std::shared_ptr<T>` | 共享所有权，引用计数控制生命周期 | 控制块 + 原始对象，额外内存/原子操作 | 多个实体共享对象，需自动释放             |\n",
    "\n",
    "**自定义删除器**在以下情况使用：\n",
    "\n",
    "- 资源需要特殊释放方式（`FILE*` with `fclose`, 自定义 `close()` API）。\n",
    "\n",
    "- 对 `unique_ptr` 设置删除器可让它管理非 `new` 的资源：\n",
    "\n",
    "  ```cpp\n",
    "  std::unique_ptr<FILE, decltype(&fclose)> fp(std::fopen(\"log.txt\", \"r\"), &fclose);\n",
    "  ```\n",
    "\n",
    "- `shared_ptr` 的删除器存放在控制块里，适合管理复杂资源或需要统计信息的场景。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 循环引用与 `std::weak_ptr`\n",
    "\n",
    "`std::shared_ptr` 通过引用计数管理对象，但若对象之间互相持有 `shared_ptr`，计数永不归零导致泄漏（循环引用）。\n",
    " 解决方案：在“非拥有”关系使用 `std::weak_ptr`：\n",
    "\n",
    "```cpp\n",
    "struct Node {\n",
    "    std::shared_ptr<Node> child;\n",
    "    std::weak_ptr<Node>   parent; // 打破环\n",
    "};\n",
    "```\n",
    "\n",
    "`std::weak_ptr`：\n",
    "\n",
    "- 不增加引用计数，只能通过 `lock()` 临时获得 `shared_ptr`，若对象已销毁则返回空。\n",
    "- 常用于观察者模式、缓存、双向指针等需要“弱引用”的场景。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# RAII 思想与现代 C++\n",
    "\n",
    "RAII = “资源获取即初始化”。核心思想：\n",
    "\n",
    "- 在对象构造时获取资源（内存、文件、锁），析构时释放。\n",
    "- 保证异常/提前返回也能自动释放，避免泄露或忘记释放。\n",
    "\n",
    "现代 C++ 中的体现：\n",
    "\n",
    "- 智能指针 (`unique_ptr`, `shared_ptr`)、锁守卫 (`std::lock_guard`)、文件/线程包装类。\n",
    "- `std::scoped_lock`, `std::unique_lock`，乃至自定义 RAII 包装器（如 `defer` 风格类）。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# `std::shared_ptr` 控制块内容与线程安全\n",
    "\n",
    "控制块（control block）是 `shared_ptr`/`weak_ptr` 共享的元数据，通常包含：\n",
    "\n",
    "1. **指向被管理对象的指针**\n",
    "   - 对 `std::make_shared` 来说，对象与控制块常在同一块内存（“EBO”/“compressed pair”，减少一次分配）。\n",
    "   - 若直接 `std::shared_ptr<T>(new T)`，对象与控制块是两次分配。\n",
    "2. **强引用计数（use count）**\n",
    "   - `shared_ptr` 的数量。归零时销毁对象，但控制块仍保留（因为可能还有 `weak_ptr`）。\n",
    "3. **弱引用计数（weak count）**\n",
    "   - 计入弱引用 + 强引用。当该计数为零时，控制块本身释放。\n",
    "4. **删除器（deleter）与分配器（allocator）**\n",
    "   - 存储在控制块内，确保释放时使用原始策略（可容纳自定义删除器/分配器）。\n",
    "\n",
    "```shell\n",
    "+---------------------------+\n",
    "| strong count              |\n",
    "| weak count                |\n",
    "| pointer / object storage  | <-- make_shared 时可能直接存放对象\n",
    "| deleter / allocator data  |\n",
    "+---------------------------+\n",
    "```\n",
    "\n",
    "**线程安全**：\n",
    "\n",
    "- 引用计数的递增/递减是原子的，因此在不同线程拷贝/销毁 `shared_ptr` 是安全的。\n",
    "- 但对共享对象本身的读写仍需同步（`shared_ptr` 只保证生命周期，不保证数据同步）。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# `std::enable_shared_from_this`\n",
    "\n",
    "作用是：**让已经由 `std::shared_ptr` 管理的对象，在其成员函数内部安全获得同一控制块的 `std::shared_ptr`/`std::weak_ptr` 引用**。这样可以：\n",
    "\n",
    "- 避免在 `this` 上再创建新的 `shared_ptr`（那样会生成新的控制块，导致同一对象有多个引用计数，进而重复析构或内存泄漏）。\n",
    "- 在对象需要把自己传递给外部 API、回调、异步任务时，确保返回的 `shared_ptr` 与外部原有的 `shared_ptr` 共享生命周期。\n",
    "- 与 `std::weak_ptr` 配合作为“自我弱引用”，实现诸如延迟任务中判断对象是否还存活等模式。\n",
    "\n",
    "只要类继承 `enable_shared_from_this<T>` 并由 `shared_ptr` 持有，就可以在成员函数里调用 `shared_from_this()`（或 `weak_from_this()`，C++17）获取安全的所有权句柄。\n",
    "\n",
    "**实现要点：**\n",
    "\n",
    "- `enable_shared_from_this` 内部维护一个 `std::weak_ptr<T> weak_this;`。\n",
    "- 当第一次通过某个 `shared_ptr<T>` 管理对象时（构造/赋值），库会在控制块中记录该 `weak_ptr` 指向相同控制块。\n",
    "- 调用 `shared_from_this()` 时，实际上是 `weak_this.lock()`，所以得到的 `shared_ptr` 与现有的 `shared_ptr` 共用同一控制块。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "#include <memory>\n",
    "#include <iostream>\n",
    "\n",
    "struct Widget : std::enable_shared_from_this<Widget> {\n",
    "    std::shared_ptr<Widget> get_self() {\n",
    "        return shared_from_this(); // 不会创建新控制块\n",
    "    }\n",
    "};\n",
    "\n",
    "int main() {\n",
    "    auto sp = std::make_shared<Widget>();\n",
    "    auto self = sp->get_self(); // self 与 sp 共享计数\n",
    "    std::cout << sp.use_count() << '\\n'; // 2\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**注意事项**：\n",
    "\n",
    "- 只能在对象已由 `shared_ptr` 管理后调用 `shared_from_this`。否则会抛出 `std::bad_weak_ptr`。\n",
    "- 若需要在 `ctor` 内调用，通常改在工厂函数或 `init` 成员中完成，确保已有 `shared_ptr`。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# `std::weak_ptr` 在缓存中的用法\n",
    "\n",
    "**场景：** 缓存中存放共享对象，但不希望缓存本身维持强引用（防止回收）。`weak_ptr` 允许缓存“观察”对象，若对象已被其他地方释放，缓存可在下次访问时清理失效条目。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "#include <memory>\n",
    "#include <unordered_map>\n",
    "#include <string>\n",
    "\n",
    "struct Data { /* ... */ };\n",
    "\n",
    "class Cache {\n",
    "public:\n",
    "    std::shared_ptr<Data> get(const std::string& key) {\n",
    "        if (auto it = table_.find(key); it != table_.end()) {\n",
    "            if (auto sp = it->second.lock()) {\n",
    "                return sp; // 缓存命中且对象仍存在\n",
    "            }\n",
    "        }\n",
    "        auto sp = load_from_source(key); // 真实加载\n",
    "        table_[key] = sp;                // 仅存 weak_ptr\n",
    "        return sp;\n",
    "    }\n",
    "\n",
    "private:\n",
    "    std::shared_ptr<Data> load_from_source(const std::string&);\n",
    "    std::unordered_map<std::string, std::weak_ptr<Data>> table_;\n",
    "};"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**优点**：\n",
    "\n",
    "- 缓存不会阻止对象销毁（无强引用）。\n",
    "- 下次访问若对象已被销毁，`lock()` 返回空，缓存即可重建或删除条目。\n",
    "\n",
    "**注意**：\n",
    "\n",
    "- 访问缓存时要处理 `lock()` 失败的情况。\n",
    "- 适合用在图像缓存、AST 节点缓存等“可重建”或“非强制驻留”资源。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# `make_unique` vs 直接构造 `unique_ptr`\n",
    "\n",
    "优势：\n",
    "\n",
    "- **异常安全**：`auto p = std::unique_ptr<T>(new T(args...));` 若 `new T` 后抛异常，在 `unique_ptr` 构造前就泄漏；`std::make_unique` 将分配与构造合在一起，避免泄漏。\n",
    "- **更简洁**：类型推导，避免重复写 `T`.\n",
    "- **性能优化**：与 `make_shared` 不同，`make_unique` 没有控制块，但仍能更高效地构造对象。\n",
    "\n",
    "为何 C++11 缺失：早期标准仅提供 `make_shared`。`make_unique` 在 C++11 中也可实现，但标准委员会直到 C++14 才正式加入，以避免二义性问题（如数组版本）。在 C++11 中通常手写模板或使用 Boost 的 `make_unique`。"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "C++17",
   "language": "C++17",
   "name": "xcpp17"
  },
  "language_info": {
   "name": "C++17"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
